﻿namespace ufida.u9.ait.openbp
{
	using System;
	using System.Collections.Generic;
    using System.Text;
    using UFIDA.U9.Base;
    using UFIDA.U9.CBO.MFG.BOM;
    using UFIDA.U9.CBO.MFG.BOM.Proxy;
    using UFIDA.U9.CBO.MFG.Enums;
    using UFIDA.U9.CBO.SCM.Item;
    using UFIDA.U9.SM.Ship;
    using UFIDA.U9.SM.SO;
    using UFSoft.UBF.AopFrame;
    using UFSoft.UBF.Business;
    using UFSoft.UBF.Util.Context;

	/// <summary>
	/// SOCreateFASItem partial 
    /// 销售订单 FAS物料生成
    /// 
	/// </summary>	
	public partial class SOCreateFASItem 
	{	
		internal BaseStrategy Select()
		{
			return new SOCreateFASItemImpementStrategy();	
		}
	}
	
	#region  implement strategy	
	/// <summary>
	/// Impement Implement
	/// 
	/// </summary>	
	internal partial class SOCreateFASItemImpementStrategy : BaseStrategy
	{
        //选配字段
        //记录选配BOM中有哪些选配项
        //用于校验用户是否多录入[大面/小面/通体/胶条]字段
        private Dictionary<string, BOMComponent> xpdic = null;

        //选配设置 [大面/小面/通体/胶条]的扩展字段设置
        private Dictionary<string, string> xpszdic = new Dictionary<string, string>()
        {
            {"大面","PrivateDescSeg11"},
            {"通体","PrivateDescSeg13"},
            {"小面","PrivateDescSeg12"},
            {"胶条","PrivateDescSeg15"}
        };

		public SOCreateFASItemImpementStrategy() { }

		public override object Do(object obj)
		{						
			SOCreateFASItem bpObj = (SOCreateFASItem)obj;

            SO so=SO.Finder.FindByID(bpObj.ID);
            if (so==null)
            {
				throw new Exception("查找SO失败!");
            }
            if(!(so.Status == SODocStatusEnum.Open || so.Status== SODocStatusEnum.Approving))
            {
                throw new Exception("订单状态不为开立或审核中");
            }

			foreach(var line in so.SOLines)
			{
				if (line.ItemInfo.ItemID == null) continue;
				if(line.ItemInfo.ItemID.ItemFormAttribute== ItemTypeAttributeEnum.Model)
				{
					//料品=模型件
					CreateFASItem(line);
				}
			}
			return null;
        }
        private void UnApproveFAS(ConfigResult config)
        {
            UnApproveConfigResultSv val = new UnApproveConfigResultSv();
            val.ConfigResult = config.Key;
            val.ConfigType = ConfigTypeEnum.SO;
            ConfigBOMDTO configBOMDTO = val.Do();
        }

        private void ApproveFAS(ConfigResult config)
        {

            ApproveConfigResultSv sv = new ApproveConfigResultSv();
            sv.SOOrg = config.Org.Key;
            sv.ConfigResult = config.Key;
            sv.ConfigResultDTO = null;
            sv.IsCreateFasItem = true;
            sv.IsCreateFasBOM = true;
            ConfigBOMDTO configBOMDTO = sv.Do();

        }
        /// <summary>
        /// 创建FAS料品,审核生成BOM以及FAS料号
        /// </summary>
        /// <param name="line"></param>
        private void CreateFASItem(SOLine line)
        {
            this.xpdic = new Dictionary<string, BOMComponent>();
            //先删除已有的FAS Config
            DeleteFASItem(line);
            //生成新的FAS config
            ConfigResult config = CreateConfig(line);
            //校验
            CheckFAS(line, config);
            //审核
            ApproveFAS(config);
            
            using(ISession session = Session.Open())
            {
                //更新SO行
                //FAS相关
                config = config.Key.GetEntity();
                line.FAS.ItemID = config.FASItem;//FAS物料
                line.FAS.ItemCode = config.FASItem.Code;
                line.FAS.ItemName = config.FASItemName;
                line.CooperatePriceStyle = PriceStyleEnum.ByAssembly;//定价方式=按母件定价
                line.ChoiceResult = config.ID;//选配结果
                line.BomOwner = line.Org;//选配组织

                //更新FAS料品名称
                //名称=原料号品名+大面+通体+小面+胶条
                List<string> strs = new List<string>();
                strs.Add(line.ItemInfo.ItemName);
                foreach (var xpsz in this.xpszdic)
                {
                    //循环字段,顺序:大面/通体/小面/胶条
                    string code = line.DescFlexField.GetValue(xpsz.Value)?.ToString();//选配料号
                    ItemMaster item = ItemMaster.Finder.Find($"Code='{code}' and Org={Context.LoginOrg.ID}");
                    if (item != null) strs.Add(item.Name);
                }
                string fasname= String.Join("_", strs);
                line.FAS.ItemName = fasname;//SO行
                config.FASItem.Name = fasname;//FAS物料
                config.FASItemName = fasname;//选配结果

                session.Commit();
            }
        }
        /// <summary>
        /// 校验 SO行[大面/小面/通体/胶条] 是否多录入
        /// </summary>
        /// <param name="line"></param>
        /// <param name="config"></param>
        private void CheckFAS(SOLine line, ConfigResult config)
        {
            if(this.xpdic==null) return;
            foreach(var xpsz in this.xpszdic)
            {
                string code = line.DescFlexField.GetValue(xpsz.Value)?.ToString();//选配料号
                if (!string.IsNullOrEmpty(code) && !this.xpdic.ContainsKey(xpsz.Key))
                {
                    //SO行上录入[大面/通体/小面/胶条]料号,但是选配BOM中不存在
                    throw new Exception($"行号[{line.DocLineNo}],不能录入选配[{xpsz.Key}]");
                }
            }
            
        }

        /// <summary>
        /// ConfigResult母件保存
        /// </summary>
        /// <param name="soline"></param>
        /// <exception cref="Exception"></exception>
        private ConfigResult CreateConfig(SOLine soline)
        {
            ConfigResult config = null;
            //查找BOM,状态=已核准,ID倒排
            string path = $"ItemMaster.Code='{soline.ItemInfo.ItemID.Code}' and Status=2 order by id desc";
            BOMMaster bom = BOMMaster.Finder.Find(path);
            if (bom == null) throw new Exception($"查找BOM失败,path:{path}");
            

            using (ISession session = Session.Open())
			{
				config = ConfigResult.Create();
				config.SrcDocNo = soline.SO.DocNo;
				config.SrcDocLineNo = soline.DocLineNo.ToString();
                //组织
                config.Org = soline.Org;
                config.ManufactureOrg = soline.Org;
                
				//BOM
                config.BOMMaster = bom.ID;
                config.BOMVersion = bom.BOMVersionCode;
                config.BOMVersionCode = bom.BOMVersionCode;
                //其他
                config.UOM = soline.PU;
                config.ItemMaster = soline.ItemInfo.ItemID;
                config.IsDisplayComponent = false;
                config.Currency = soline.SO.TC;
                config.ConfigResultGUID = Guid.Empty.ToString();
                config.SrcDocApproveStyle = 1;
                config.PriceStyle = bom.PriceStyle.Value;
                config.PriceList = 0;

                //创建行
                int rowno = 0;
				foreach(var item in bom.BOMComponents)
				{
                    if (item.IsEffective == false) continue;

					rowno += 10;
					ConfigResultLine line = ConfigResultLine.Create(config);
					line.LineNum = rowno;
					line.Sequence = item.Sequence;//子件项次
                    line.SupplyWareHouse = item.SupplyWareHouse;
					line.ParentQty=item.ParentQty;
					line.OpSequence = item.OperationNum;
					line.MinSelectedQty = item.MinSelectedQty;
					line.MaxSelectedQty=item.MaxSelectedQty;
					
					line.IsSelected = true;//选择
					line.IsPrint = item.IsPrint;//打印
                    line.IsMandatory = item.IsMandatory;//参与选配
                    line.IsExclude = item.IsExclude;//选项互斥
					line.IsCalcPrice = item.IsCalcPrice;//计算价格
                    line.IsDefault = item.IsDefault;//是否默认

                    line.ConfigResultLineGUID=Guid.NewGuid().ToString();
					line.ComponentUsageUOM = item.IssueUOM;//用量单位
					line.ComponentUsage = item.UsageQty;//子件用量
					line.ComponentItem = item.ItemMaster;
					line.BOMComponent = item.ID;
                    line.IsWholeSetIssue = item.IsWholeSetIssue;
                    line.SetChkAtComplete = item.SetChkAtComplete;

                    if (item.ItemMaster.ItemFormAttribute== ItemTypeAttributeEnum.OptionClass
                        || item.ItemMaster.ItemFormAttribute == ItemTypeAttributeEnum.Model)
					{
						//如果子件是可选类/模型,需要递归展开
						CreateConfig(soline,config, line);

                    }
                }
                session.Commit();
			}

            return config;
        }
        /// <summary>
        /// ConfigResult子件,可选类保存
		/// 递归处理,如果子件是可选类/模型,需要递归展开
        /// ConfigResult母件保存时调用
        /// </summary>
        /// <param name="soline">订单行</param>
        /// <param name="pconfig">母件config</param>
        /// <param name="pline">母件config行</param>
        private void CreateConfig(SOLine soline,ConfigResult pconfig, ConfigResultLine pline)
        {
            //查找BOM 物料=选配行:物料,状态=已核准,ID倒排
            string path = $"ItemMaster.Code='{pline.ComponentItem.Code}' and Status=2 order by id desc";
            BOMMaster bom = BOMMaster.Finder.Find(path);
            if (bom == null) throw new Exception($"查找BOM失败,path:{path}");


            using (ISession session = Session.Open())
            {
                ConfigResult config = ConfigResult.Create();
                config.ParentConfigResult = pconfig;
                //组织
                config.Org = pconfig.Org;
                config.ManufactureOrg = pconfig.Org;
                config.PriceListOrg = pconfig.Org;
                
                //BOM
                config.BOMMaster = bom.ID;
                config.BOMVersion = bom.BOMVersionCode;
                config.BOMVersionCode = bom.BOMVersionCode;

                //其他
                config.UOM = soline.PU;
                config.ItemMaster = pline.ComponentItem;
                config.IsDisplayComponent = true;
                config.Currency = pconfig.Currency;
                config.ConfigResultGUID = pline.ConfigResultLineGUID;
                config.SrcDocApproveStyle = 1;
                config.PriceStyle = bom.PriceStyle.Value;
                config.PriceList = -1;

                //创建行
                //可选类config行保存bom所有子项,通过IsSelected判断是否选择该子项
                int rowno = 0;
                foreach (var item in bom.BOMComponents)
                {
                    if (item.IsEffective == false) continue;

                    rowno += 10;
                    ConfigResultLine line = ConfigResultLine.Create(config);
                    line.LineNum = rowno;
                    line.Sequence = item.Sequence;//子件项次
                    line.SupplyWareHouse = item.SupplyWareHouse;
                    line.ParentQty = item.ParentQty;
                    line.OpSequence = item.OperationNum;
                    line.MinSelectedQty = item.MinSelectedQty;
                    line.MaxSelectedQty = item.MaxSelectedQty;

                    line.IsSelected = GetIsSelected(soline, bom, item);//选择
                    line.IsPrint = item.IsPrint;//打印
                    line.IsMandatory = item.IsMandatory;//参与选配
                    line.IsExclude = item.IsExclude;//选项互斥
                    line.IsCalcPrice = item.IsCalcPrice;//计算价格
                    line.IsDefault = item.IsDefault;//是否默认

                    line.ConfigResultLineGUID = Guid.NewGuid().ToString();
                    line.ComponentUsageUOM = item.IssueUOM;//用量单位
                    line.ComponentUsage = item.UsageQty;//子件用量
                    line.ComponentItem = item.ItemMaster;
                    line.BOMComponent = item.ID;
                    line.IsWholeSetIssue = item.IsWholeSetIssue;
                    line.SetChkAtComplete = item.SetChkAtComplete;

                    if (item.ItemMaster.ItemFormAttribute == ItemTypeAttributeEnum.OptionClass)
                    {
                        //如果子件是可选类,需要递归展开
                        CreateConfig(soline, config, line);
                    }
                }

                //ConfigResult选配检查,选配行必须有一个IsSelected=true
                if (!HasSelected(config))
                    throw new Exception($"行号:[{soline.DocLineNo}],选配件[{bom.DescFlexField.PrivateDescSeg1}],子件料号:[{bom.ItemMaster.Code}],未找到选择结果");
                session.Commit();
            }
        }
        /// <summary>
        /// 检查ConfigResult的行中,必须有一个IsSelected=true
        /// </summary>
        /// <param name="config"></param>
        /// <returns></returns>
        private static bool HasSelected(ConfigResult config)
        {
            foreach (var item in config.ConfigResultLines)
            {
                if (item.IsSelected) return true;
            }
            return false;
        }

        /// <summary>
        /// 判断soline上填写的选配项是否是该bom子项
        /// 母件=模型,其子件都是选择
        /// 母件=可选类,其子件手工选择
        /// 其他,默认选择
        /// </summary>
        /// <param name="soline">订单行</param>
        /// <param name="bom">选配bom</param>
        /// <param name="bomline">bom子件</param>
        /// <returns>是否选择项,选择项只会有一个</returns>
        private bool GetIsSelected(SOLine soline, BOMMaster bom, BOMComponent bomline)
        {

            if (bom.ItemMaster.ItemFormAttribute == ItemTypeAttributeEnum.Model)
            {
                //BOM母项=模型
                return true;
            }
            else if (bom.ItemMaster.ItemFormAttribute == ItemTypeAttributeEnum.OptionClass)
            {
                //BOM母项=可选类
                String xpcode = "";//SO行上录入的选配件编码
                //依据BOM设置,获取SO行上的 物料编码=大面/小面/通体/胶条对应物料编码
                if (string.IsNullOrEmpty(bom.DescFlexField.PrivateDescSeg1))
                    throw new Exception($"行号:[{soline.DocLineNo}],料号:[{bom.ItemMaster.Code}],未设置[大面/小面/通体/胶条等]BOM选配名称");
                if (bom.DescFlexField.PrivateDescSeg1 == "大面")
                {
                    xpcode = soline.DescFlexField.PrivateDescSeg11;
                }
                else if (bom.DescFlexField.PrivateDescSeg1 == "小面")
                {
                    xpcode = soline.DescFlexField.PrivateDescSeg12;
                }
                else if (bom.DescFlexField.PrivateDescSeg1 == "通体")
                {
                    xpcode = soline.DescFlexField.PrivateDescSeg13;
                }
                else if (bom.DescFlexField.PrivateDescSeg1 == "胶条")
                {
                    xpcode = soline.DescFlexField.PrivateDescSeg15;
                }
                if (string.IsNullOrEmpty(xpcode))
                    throw new Exception($"行号:[{soline.DocLineNo}],选配件[{bom.DescFlexField.PrivateDescSeg1}],未录入!");

                //如果SO选择物料编码=BOM行:物料编码,代表soline上用户选择该BOM子项
                if (xpcode == bomline.ItemMaster.Code)
                {
                    //bom.DescFlexField.PrivateDescSeg1代表 大面/小面等选项
                    //bomline 被选配上的bom子项
                    if (this.xpdic != null && this.xpdic.ContainsKey(bom.DescFlexField.PrivateDescSeg1))
                    {
                        BOMComponent comp1 = this.xpdic[bom.DescFlexField.PrivateDescSeg1];
                        String err = $"选配项[{bom.DescFlexField.PrivateDescSeg1}]存在重复BOM!" +
                            $"BOM1:[{comp1.BOMMaster.ItemMaster.Code}]/[{comp1.ItemMaster.Code}]," +
                            $"BOM2:[{bomline.BOMMaster.ItemMaster.Code}]/[{bomline.ItemMaster.Code}]";
                        throw new Exception(err);
                    }
                    else
                    {
                        this.xpdic.Add(bom.DescFlexField.PrivateDescSeg1, bomline);
                    }
                    return true;
                }
                else
                    return false;
            }
            else
            {
                return true;
            }

        }


        /// <summary>
        /// 弃审ConfigResult
        /// 清除SO FAS物料
        /// 递归删除ConfigResult选配结果
        /// </summary>
        /// <param name="line">so line</param>
        private void DeleteFASItem(SOLine line)
        {
			string path = $"SrcDocNo='{line.SO.DocNo}' and SrcDocLineNo={line.DocLineNo}";
			ConfigResult config = ConfigResult.Finder.Find(path);
			if (config == null) return;

            //弃审
            if(config.Status== ConfigResultStatusEnum.Approved)
            {
                UnApproveFAS(config);
            }

            //清除SO引用
            //弃审后才能清除SO字段,否则弃审报错
            using (ISession session1 = Session.Open())
            {
                line.FAS.ItemID = null;
                line.FAS.ItemCode = null;
                line.FAS.ItemName = null;
                line.CooperatePriceStyle = PriceStyleEnum.Empty;
                line.ChoiceResult = -1;
                line.BomOwner = null;

                session1.Commit();
            }

            //删除配置
            //删除前需要清除SO引用字段,否则报错
            using (ISession session = Session.Open())
			{
                //config = config.Key.GetEntity();
                //递归删除下级
                DeleteSubConfig(config);
				//删除本级
				session.InList(config);
                config.Remove();
				session.Commit();
			}
        }

		private void DeleteSubConfig(ConfigResult pconfig)
		{
			string path = $"ParentConfigResult={pconfig.ID}";
			ConfigResult.EntityList configList = ConfigResult.Finder.FindAll(path);
			if (configList == null || configList.Count == 0) return;

			foreach (var config in configList)
			{
				//递归删除
				DeleteSubConfig(config);

				//删除本级
				config.Remove();
			}

		}
    }

	#endregion
	
	
}